package top.magicpotato.sample.service;

import javafx.application.Platform;
import javafx.scene.control.TreeItem;
import javafx.util.Duration;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.*;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.pomo.toasterfx.model.ToastParameter;
import top.magicpotato.sample.component.ToastBar;
import top.magicpotato.sample.pojo.record.ConnectionInfo;
import top.magicpotato.sample.pojo.record.MybatisGenBaseInfo;
import top.magicpotato.sample.pojo.record.MybatisGenTableInfo;
import top.magicpotato.sample.store.DbStore;

import java.sql.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

public class MainService {

    private static final MainService instance = new MainService();

    public void initTableTree(TreeItem<String> dbTreeItem) {
        if (dbTreeItem.getChildren().size() > 0) {
            // 如果有数据了 就先清空了在重新赋值
            dbTreeItem.getChildren().clear();
        }
        ConnectionInfo connectionInfo = DbStore.get(dbTreeItem.getValue());
        CompletableFuture.supplyAsync(() ->
                getTable(connectionInfo)
        ).orTimeout(2, TimeUnit.SECONDS).whenComplete((table, e) -> {
            if (table == null || table.isEmpty()) {
                ToastBar.getInstant().fail("提示", "连接失败", ToastParameter.builder().timeout(Duration.seconds(2)).build());
            } else {
                Platform.runLater(() -> {
                    dbTreeItem.getChildren().addAll(table);
                    dbTreeItem.setExpanded(true);
                    ToastBar.getInstant().success("提示", "连接成功", ToastParameter.builder().timeout(Duration.seconds(2)).build());
                });
            }
        });


    }

    public List<TreeItem<String>> getTable(ConnectionInfo connectionInfo) {
        if (connectionInfo == null) {
            return List.of();
        }
        try {
            List<TreeItem<String>> result = new LinkedList<>();
            String jdbcUrl = "jdbc:mysql://" + connectionInfo.host();
            Properties properties = new Properties();
            properties.setProperty("user", connectionInfo.username());
            properties.setProperty("password", connectionInfo.username());
            properties.setProperty("useUnicode", connectionInfo.useUnicode().toString());
            properties.setProperty("characterEncoding", connectionInfo.characterEncoding());
            properties.setProperty("useSSL", connectionInfo.useSSL().toString());
            properties.setProperty("serverTimezone", connectionInfo.serverTimezone());
            properties.setProperty("allowPublicKeyRetrieval", connectionInfo.allowPublicKeyRetrieval().toString());

            Connection connection = DriverManager.getConnection(jdbcUrl, properties);

            String sql = "select * from information_schema.TABLES t  where TABLE_SCHEMA = ?";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, connectionInfo.dbName());
            ResultSet rs = preparedStatement.executeQuery();
            while (rs.next()) {
                result.add(new TreeItem<>(rs.getString("TABLE_NAME")));
            }

            rs.close();
            preparedStatement.close();
            connection.close();
            return result;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return List.of();
    }

    public boolean mybatisGenerator(ConnectionInfo connectionInfo, MybatisGenBaseInfo mybatisGenBaseInfo, MybatisGenTableInfo mybatisGenTableInfo) {
        try {
            List<String> warnings = new ArrayList<>();
            boolean overwrite = true;
            Configuration config = new Configuration();

            Context context = new Context(null);
            context.setId("DB2Tables");
            context.setTargetRuntime("MyBatis3");
            CommentGeneratorConfiguration commentGeneratorConfiguration = new CommentGeneratorConfiguration();
            commentGeneratorConfiguration.addProperty("suppressAllComments", "true");
            context.setCommentGeneratorConfiguration(commentGeneratorConfiguration);

            JDBCConnectionConfiguration jdbcConnectionConfiguration = new JDBCConnectionConfiguration();
            String jdbcUrl = "jdbc:mysql://" + connectionInfo.host();
            jdbcConnectionConfiguration.setConnectionURL(jdbcUrl);
            jdbcConnectionConfiguration.setUserId(connectionInfo.username());
            jdbcConnectionConfiguration.setPassword(connectionInfo.password());
            jdbcConnectionConfiguration.setDriverClass("com.mysql.cj.jdbc.Driver");
            jdbcConnectionConfiguration.addProperty("useInformationSchema", connectionInfo.useInformationSchema().toString());
            jdbcConnectionConfiguration.addProperty("remarks", connectionInfo.remarks().toString());
            jdbcConnectionConfiguration.addProperty("useUnicode", connectionInfo.useUnicode().toString());
            jdbcConnectionConfiguration.addProperty("characterEncoding", connectionInfo.characterEncoding());
            jdbcConnectionConfiguration.addProperty("useSSL", connectionInfo.useSSL().toString());
            jdbcConnectionConfiguration.addProperty("serverTimezone", connectionInfo.serverTimezone());
            jdbcConnectionConfiguration.addProperty("allowPublicKeyRetrieval", connectionInfo.allowPublicKeyRetrieval().toString());

            context.setJdbcConnectionConfiguration(jdbcConnectionConfiguration);

            JavaModelGeneratorConfiguration javaModelGeneratorConfiguration = new JavaModelGeneratorConfiguration();
            javaModelGeneratorConfiguration.setTargetPackage(mybatisGenBaseInfo.modulePackage());
            javaModelGeneratorConfiguration.setTargetProject(mybatisGenBaseInfo.targetProject());
            context.setJavaModelGeneratorConfiguration(javaModelGeneratorConfiguration);

            SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration = new SqlMapGeneratorConfiguration();
            sqlMapGeneratorConfiguration.setTargetPackage(mybatisGenBaseInfo.xmlPackage());
            sqlMapGeneratorConfiguration.setTargetProject(mybatisGenBaseInfo.targetProject());
            context.setSqlMapGeneratorConfiguration(sqlMapGeneratorConfiguration);

            JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = new JavaClientGeneratorConfiguration();
            javaClientGeneratorConfiguration.setTargetPackage(mybatisGenBaseInfo.mapperPackage());
            javaClientGeneratorConfiguration.setTargetProject(mybatisGenBaseInfo.targetProject());
            javaClientGeneratorConfiguration.setConfigurationType("XMLMAPPER");
            context.setJavaClientGeneratorConfiguration(javaClientGeneratorConfiguration);


            TableConfiguration tc = new TableConfiguration(context);
            tc.setTableName(mybatisGenTableInfo.tableName());
            tc.setAlias(mybatisGenTableInfo.tableAlia());
//            tc.setSchema(connectionInfo.dbName());
            tc.setCatalog(connectionInfo.dbName());

            tc.setCountByExampleStatementEnabled(mybatisGenTableInfo.countByExample());
            tc.setSelectByExampleStatementEnabled(mybatisGenTableInfo.selectByExample());
            tc.setDeleteByExampleStatementEnabled(mybatisGenTableInfo.deleteByExample());
            tc.setUpdateByExampleStatementEnabled(mybatisGenTableInfo.updateByExample());

            context.addTableConfiguration(tc);

            config.addContext(context);
            DefaultShellCallback callback = new DefaultShellCallback(overwrite);
            MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
            myBatisGenerator.generate(null);
            System.out.println(warnings);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public static MainService getInstance() {
        return instance;
    }
}
